"""
原创度报告生成器
"""
import os
import json
from typing import Dict, Any, List, Optional
from datetime import datetime
from dataclasses import dataclass, asdict
from io import BytesIO
import base64

from jinja2 import Environment, Template, FileSystemLoader
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, PageBreak, Image
from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.piecharts import Pie
from reportlab.graphics.charts.barcharts import VerticalBarChart

from src.models.fingerprint import OriginalityReport, SimilarContent
from src.detectors.originality_detector import DetectionResult


@dataclass
class ReportData:
    """报告数据结构"""
    report_id: str
    content_id: str
    title: str
    originality_score: float
    total_segments: int
    similar_segments_count: int
    similar_contents: List[SimilarContent]
    citations_needed: List[Dict[str, Any]]
    detection_time: datetime
    word_count: int
    summary: str
    metadata: Dict[str, Any]


class OriginalityReportGenerator:
    """原创度报告生成器"""
    
    # HTML模板
    HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原创性检测报告</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f5f5f5;
        }
        .report-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            border-radius: 10px;
            margin-bottom: 30px;
        }
        .report-title {
            font-size: 28px;
            margin-bottom: 10px;
        }
        .report-meta {
            opacity: 0.9;
            font-size: 14px;
        }
        .score-card {
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            text-align: center;
            margin-bottom: 30px;
        }
        .score-circle {
            width: 150px;
            height: 150px;
            margin: 0 auto 20px;
            position: relative;
        }
        .score-value {
            font-size: 48px;
            font-weight: bold;
            color: {% if originality_score >= 90 %}#4CAF50{% elif originality_score >= 70 %}#FFC107{% else %}#f44336{% endif %};
        }
        .score-label {
            font-size: 18px;
            color: #666;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        .stat-card {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .stat-value {
            font-size: 32px;
            font-weight: bold;
            color: #667eea;
        }
        .stat-label {
            font-size: 14px;
            color: #666;
            margin-top: 5px;
        }
        .similar-content {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
        .similar-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }
        .similarity-badge {
            background: #ff5722;
            color: white;
            padding: 5px 15px;
            border-radius: 20px;
            font-size: 14px;
        }
        .similar-segments {
            background: #f8f8f8;
            padding: 15px;
            border-radius: 5px;
            margin-top: 10px;
        }
        .segment-item {
            padding: 10px;
            margin: 10px 0;
            background: white;
            border-left: 3px solid #ff5722;
            border-radius: 3px;
        }
        .citation-suggestion {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px;
            margin: 10px 0;
            border-radius: 3px;
        }
        .chart-container {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }
        .footer {
            text-align: center;
            color: #666;
            margin-top: 50px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <div class="report-header">
        <h1 class="report-title">原创性检测报告</h1>
        <div class="report-meta">
            <p>报告ID: {{ report_id }}</p>
            <p>生成时间: {{ detection_time }}</p>
            <p>文档标题: {{ title }}</p>
        </div>
    </div>
    
    <div class="score-card">
        <div class="score-circle">
            <canvas id="scoreChart"></canvas>
        </div>
        <div class="score-value">{{ originality_score }}%</div>
        <div class="score-label">原创度评分</div>
        <p>{{ summary }}</p>
    </div>
    
    <div class="stats-grid">
        <div class="stat-card">
            <div class="stat-value">{{ word_count }}</div>
            <div class="stat-label">总字数</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">{{ total_segments }}</div>
            <div class="stat-label">检测段落数</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">{{ similar_segments_count }}</div>
            <div class="stat-label">相似段落数</div>
        </div>
        <div class="stat-card">
            <div class="stat-value">{{ citations_count }}</div>
            <div class="stat-label">需要引用数</div>
        </div>
    </div>
    
    <div class="chart-container">
        <h2>相似度分布图</h2>
        <canvas id="distributionChart"></canvas>
    </div>
    
    {% if similar_contents %}
    <h2>相似内容详情</h2>
    {% for similar in similar_contents %}
    <div class="similar-content">
        <div class="similar-header">
            <h3>相似内容 #{{ loop.index }}</h3>
            <span class="similarity-badge">相似度: {{ similar.similarity }}%</span>
        </div>
        <p><strong>来源:</strong> {{ similar.source }}</p>
        <div class="similar-segments">
            <h4>相似段落:</h4>
            {% for segment in similar.segments %}
            <div class="segment-item">
                {{ segment.text[:200] }}{% if segment.text|length > 200 %}...{% endif %}
            </div>
            {% endfor %}
        </div>
    </div>
    {% endfor %}
    {% endif %}
    
    {% if citations_needed %}
    <h2>引用建议</h2>
    {% for citation in citations_needed %}
    <div class="citation-suggestion">
        <strong>位置:</strong> 第{{ citation.position }}处<br>
        <strong>建议:</strong> {{ citation.suggestion }}<br>
        <strong>优先级:</strong> {{ citation.priority }}
    </div>
    {% endfor %}
    {% endif %}
    
    <div class="footer">
        <p>© 2025 原创性检测系统 - 报告生成时间: {{ detection_time }}</p>
    </div>
    
    <script>
        // 绘制原创度环形图
        const scoreCtx = document.getElementById('scoreChart').getContext('2d');
        new Chart(scoreCtx, {
            type: 'doughnut',
            data: {
                datasets: [{
                    data: [{{ originality_score }}, {{ 100 - originality_score }}],
                    backgroundColor: [
                        {% if originality_score >= 90 %}'#4CAF50'{% elif originality_score >= 70 %}'#FFC107'{% else %}'#f44336'{% endif %},
                        '#e0e0e0'
                    ],
                    borderWidth: 0
                }]
            },
            options: {
                cutout: '70%',
                plugins: {
                    legend: { display: false },
                    tooltip: { enabled: false }
                }
            }
        });
        
        // 绘制相似度分布图
        const distCtx = document.getElementById('distributionChart').getContext('2d');
        new Chart(distCtx, {
            type: 'bar',
            data: {
                labels: ['0-20%', '20-40%', '40-60%', '60-80%', '80-100%'],
                datasets: [{
                    label: '段落数',
                    data: {{ distribution_data }},
                    backgroundColor: 'rgba(102, 126, 234, 0.6)',
                    borderColor: 'rgba(102, 126, 234, 1)',
                    borderWidth: 1
                }]
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true,
                        ticks: { stepSize: 1 }
                    }
                }
            }
        });
    </script>
</body>
</html>
    """
    
    def __init__(self, template_dir: Optional[str] = None):
        """
        初始化报告生成器
        
        Args:
            template_dir: 模板目录路径
        """
        self.template_dir = template_dir
        if template_dir and os.path.exists(template_dir):
            self.env = Environment(loader=FileSystemLoader(template_dir))
        else:
            self.env = Environment()
            self.env.from_string(self.HTML_TEMPLATE)
    
    def generate_html_report(
        self,
        detection_result: DetectionResult,
        report_data: ReportData,
        output_path: Optional[str] = None
    ) -> str:
        """
        生成HTML报告
        
        Args:
            detection_result: 检测结果
            report_data: 报告数据
            output_path: 输出文件路径
            
        Returns:
            HTML内容或文件路径
        """
        # 计算相似度分布
        distribution = self._calculate_distribution(detection_result)
        
        # 准备模板数据
        template_data = {
            'report_id': report_data.report_id,
            'title': report_data.title,
            'originality_score': round(report_data.originality_score, 1),
            'total_segments': report_data.total_segments,
            'similar_segments_count': report_data.similar_segments_count,
            'word_count': report_data.word_count,
            'citations_count': len(report_data.citations_needed),
            'detection_time': report_data.detection_time.strftime('%Y-%m-%d %H:%M:%S'),
            'summary': report_data.summary,
            'similar_contents': self._format_similar_contents(report_data.similar_contents),
            'citations_needed': report_data.citations_needed,
            'distribution_data': json.dumps(distribution)
        }
        
        # 渲染模板
        if self.template_dir:
            template = self.env.get_template('originality_report.html')
        else:
            template = self.env.from_string(self.HTML_TEMPLATE)
        
        html_content = template.render(**template_data)
        
        # 保存到文件
        if output_path:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(html_content)
            return output_path
        
        return html_content
    
    def generate_pdf_report(
        self,
        detection_result: DetectionResult,
        report_data: ReportData,
        output_path: str
    ) -> str:
        """
        生成PDF报告
        
        Args:
            detection_result: 检测结果
            report_data: 报告数据
            output_path: 输出文件路径
            
        Returns:
            文件路径
        """
        # 创建PDF文档
        doc = SimpleDocTemplate(
            output_path,
            pagesize=A4,
            rightMargin=72,
            leftMargin=72,
            topMargin=72,
            bottomMargin=18
        )
        
        # 获取样式
        styles = getSampleStyleSheet()
        styles.add(ParagraphStyle(
            name='ChineseTitle',
            parent=styles['Title'],
            fontName='Helvetica-Bold',
            fontSize=24,
            alignment=TA_CENTER,
            spaceAfter=30
        ))
        styles.add(ParagraphStyle(
            name='ChineseBody',
            parent=styles['Normal'],
            fontName='Helvetica',
            fontSize=12,
            alignment=TA_JUSTIFY
        ))
        
        # 构建PDF内容
        story = []
        
        # 标题
        story.append(Paragraph("原创性检测报告", styles['ChineseTitle']))
        story.append(Spacer(1, 12))
        
        # 基本信息表格
        info_data = [
            ['报告ID', report_data.report_id],
            ['文档标题', report_data.title],
            ['检测时间', report_data.detection_time.strftime('%Y-%m-%d %H:%M:%S')],
            ['总字数', str(report_data.word_count)]
        ]
        info_table = Table(info_data, colWidths=[2*inch, 4*inch])
        info_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), colors.beige),
            ('TEXTCOLOR', (0, 0), (-1, -1), colors.black),
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
            ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
            ('FONTSIZE', (0, 0), (-1, -1), 12),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
            ('GRID', (0, 0), (-1, -1), 1, colors.black)
        ]))
        story.append(info_table)
        story.append(Spacer(1, 20))
        
        # 原创度评分
        score_color = colors.green if report_data.originality_score >= 90 else \
                     colors.orange if report_data.originality_score >= 70 else colors.red
        
        score_data = [
            ['原创度评分', f'{report_data.originality_score:.1f}%'],
            ['检测段落数', str(report_data.total_segments)],
            ['相似段落数', str(report_data.similar_segments_count)],
            ['需要引用数', str(len(report_data.citations_needed))]
        ]
        score_table = Table(score_data, colWidths=[2*inch, 4*inch])
        score_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (0, 0), colors.grey),
            ('BACKGROUND', (1, 0), (1, 0), score_color),
            ('TEXTCOLOR', (0, 0), (-1, -1), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, -1), 'Helvetica-Bold'),
            ('FONTSIZE', (1, 0), (1, 0), 16),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
            ('GRID', (0, 0), (-1, -1), 1, colors.black)
        ]))
        story.append(score_table)
        story.append(Spacer(1, 20))
        
        # 检测摘要
        story.append(Paragraph("检测摘要", styles['Heading2']))
        story.append(Paragraph(report_data.summary, styles['ChineseBody']))
        story.append(Spacer(1, 20))
        
        # 相似内容详情
        if report_data.similar_contents:
            story.append(PageBreak())
            story.append(Paragraph("相似内容详情", styles['Heading2']))
            
            for idx, similar in enumerate(report_data.similar_contents[:5], 1):
                story.append(Paragraph(f"相似内容 #{idx}", styles['Heading3']))
                similar_data = [
                    ['来源', similar.source if hasattr(similar, 'source') else 'Unknown'],
                    ['相似度', f'{similar.similarity:.1f}%' if hasattr(similar, 'similarity') else 'N/A'],
                    ['段落数', str(len(similar.segments)) if hasattr(similar, 'segments') else '0']
                ]
                similar_table = Table(similar_data, colWidths=[2*inch, 4*inch])
                similar_table.setStyle(TableStyle([
                    ('BACKGROUND', (0, 0), (-1, -1), colors.lightgrey),
                    ('GRID', (0, 0), (-1, -1), 1, colors.black)
                ]))
                story.append(similar_table)
                story.append(Spacer(1, 12))
        
        # 引用建议
        if report_data.citations_needed:
            story.append(PageBreak())
            story.append(Paragraph("引用建议", styles['Heading2']))
            
            for citation in report_data.citations_needed[:10]:
                citation_text = f"位置: {citation.get('position', 'Unknown')}\n"
                citation_text += f"建议: {citation.get('suggestion', 'Add citation')}\n"
                citation_text += f"优先级: {citation.get('priority', 'Medium')}"
                story.append(Paragraph(citation_text, styles['ChineseBody']))
                story.append(Spacer(1, 12))
        
        # 生成PDF
        doc.build(story)
        
        return output_path
    
    def generate_json_report(
        self,
        detection_result: DetectionResult,
        report_data: ReportData,
        output_path: Optional[str] = None
    ) -> str:
        """
        生成JSON格式报告
        
        Args:
            detection_result: 检测结果
            report_data: 报告数据
            output_path: 输出文件路径
            
        Returns:
            JSON字符串或文件路径
        """
        # 准备JSON数据
        json_data = {
            'report_id': report_data.report_id,
            'content_id': report_data.content_id,
            'title': report_data.title,
            'originality_score': report_data.originality_score,
            'detection_time': report_data.detection_time.isoformat(),
            'statistics': {
                'word_count': report_data.word_count,
                'total_segments': report_data.total_segments,
                'similar_segments_count': report_data.similar_segments_count,
                'citations_needed': len(report_data.citations_needed)
            },
            'summary': report_data.summary,
            'similar_contents': [
                {
                    'content_id': sc.content_id if hasattr(sc, 'content_id') else None,
                    'similarity': sc.similarity if hasattr(sc, 'similarity') else 0,
                    'source': sc.source if hasattr(sc, 'source') else None,
                    'segments_count': len(sc.segments) if hasattr(sc, 'segments') else 0
                }
                for sc in report_data.similar_contents
            ],
            'citations_needed': report_data.citations_needed,
            'metadata': report_data.metadata
        }
        
        # 转换为JSON字符串
        json_str = json.dumps(json_data, ensure_ascii=False, indent=2, default=str)
        
        # 保存到文件
        if output_path:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(json_str)
            return output_path
        
        return json_str
    
    def _calculate_distribution(self, detection_result: DetectionResult) -> List[int]:
        """
        计算相似度分布
        
        Args:
            detection_result: 检测结果
            
        Returns:
            分布数据 [0-20%, 20-40%, 40-60%, 60-80%, 80-100%]
        """
        distribution = [0, 0, 0, 0, 0]
        
        if hasattr(detection_result, 'segment_results'):
            for segment in detection_result.segment_results:
                if hasattr(segment, 'max_similarity'):
                    similarity = segment.max_similarity * 100
                    if similarity <= 20:
                        distribution[0] += 1
                    elif similarity <= 40:
                        distribution[1] += 1
                    elif similarity <= 60:
                        distribution[2] += 1
                    elif similarity <= 80:
                        distribution[3] += 1
                    else:
                        distribution[4] += 1
        
        return distribution
    
    def _format_similar_contents(self, similar_contents: List[SimilarContent]) -> List[Dict[str, Any]]:
        """
        格式化相似内容用于显示
        
        Args:
            similar_contents: 相似内容列表
            
        Returns:
            格式化后的数据
        """
        formatted = []
        
        for sc in similar_contents[:10]:  # 最多显示10个
            formatted_sc = {
                'source': sc.source if hasattr(sc, 'source') else 'Unknown',
                'similarity': round(sc.similarity * 100, 1) if hasattr(sc, 'similarity') else 0,
                'segments': []
            }
            
            if hasattr(sc, 'segments'):
                for segment in sc.segments[:5]:  # 每个相似内容最多显示5个段落
                    formatted_sc['segments'].append({
                        'text': segment.get('text', '') if isinstance(segment, dict) else str(segment)
                    })
            
            formatted.append(formatted_sc)
        
        return formatted
    
    async def save_report_to_db(
        self,
        report_data: ReportData,
        repository: Any
    ) -> str:
        """
        保存报告到数据库
        
        Args:
            report_data: 报告数据
            repository: 数据库仓库
            
        Returns:
            报告ID
        """
        report = OriginalityReport(
            content_id=report_data.content_id,
            originality_score=report_data.originality_score,
            similar_contents=report_data.similar_contents,
            citations_needed=report_data.citations_needed,
            checked_at=report_data.detection_time,
            report_url=f"/reports/{report_data.report_id}.html"
        )
        
        return await repository.save_report(report)
    
    def generate_summary(
        self,
        originality_score: float,
        total_segments: int,
        similar_segments: int
    ) -> str:
        """
        生成检测摘要
        
        Args:
            originality_score: 原创度分数
            total_segments: 总段落数
            similar_segments: 相似段落数
            
        Returns:
            摘要文本
        """
        if originality_score >= 90:
            level = "极高"
            desc = "内容原创性极高，几乎没有发现相似内容。"
        elif originality_score >= 80:
            level = "高"
            desc = "内容原创性较高，仅发现少量相似内容。"
        elif originality_score >= 70:
            level = "中等"
            desc = "内容原创性中等，发现部分相似内容，建议适当修改。"
        elif originality_score >= 60:
            level = "偏低"
            desc = "内容原创性偏低，发现较多相似内容，需要进行改写。"
        else:
            level = "低"
            desc = "内容原创性较低，存在大量相似内容，强烈建议重新创作。"
        
        summary = f"本文档原创度为{level}（{originality_score:.1f}%）。"
        summary += f"共检测{total_segments}个段落，其中{similar_segments}个段落存在相似内容。"
        summary += desc
        
        return summary